/**   
 * @Title: SearchSimilarImgImpl.java 
 * @Package net.gdface.service.search 
 * @Description: TODO 
 * @author guyadong   
 * @date 2015年5月8日 下午6:12:26 
 * @version V1.0   
 */
package net.gdface.service.search;

import java.net.URI;

import net.gdface.httpclient.FailOpenPage;
import net.gdface.httpclient.SyncClientManager;
import net.gdface.utils.Assert;
import net.gdface.utils.Judge;
import net.gdface.worker.QueueManager;

import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author guyadong
 *
 */
public abstract class SearchSimilarImgImpl extends SearchImgAbstractImpl implements SearchSimilarImg {
	private static final Logger logger = LoggerFactory.getLogger(SearchSimilarImgImpl.class);
	private final QueueManager<RemoteImageWOC> queueManager;
	private String md5Ref = null;
	protected URI location;
	protected JSONObject jsonResp;
	protected URI srcImg;
	protected URI webPage;
	protected int startIndex=0;
	protected int totalImage=-1;

	protected abstract String getArrayKey();

	protected abstract ImgJsonDecoder getImgJsonDecoder();

	protected abstract URI nextPage(URI lastPage, int pageNum);

	protected abstract URI createHTMLUri();
	abstract protected boolean isLast();
	/**
	 * 从{@link #jsonResp}中获取结果总数
	 * @return
	 */
	protected abstract int getTotal();

	/**
	 * 从{@link #jsonResp}中获取结果每页的数量
	 * @return
	 */
	protected abstract int getPageSize();

	/**
	 * 根据 {@link #jsonResp}自身携带的信息判断其是不是有效的返回值
	 * @return
	 * @throws JSONException 
	 */
	protected abstract boolean isValidResp() throws JSONException;

	public SearchSimilarImgImpl(QueueManager<RemoteImageWOC> queueManager) {
		super();
		this.queueManager = queueManager;
	}

	@Override
	public void setMd5Ref(String md5Ref) {
		this.md5Ref = md5Ref;
	}

	@Override
	public JSONArray getImgInfoFromSE(URI srcUri, String keyword) throws FailOpenPage, InterruptedException,
			IllegalArgumentException {
		Assert.notNull(srcUri, "srcUri");
		Assert.notEmpty(keyword, "keyword");
		this.srcImg = srcUri;
		this.webPage = createHTMLUri();
		String locationStr = null;
		try {
			locationStr = SyncClientManager.getInstance().getLocation(webPage, -1);
		} catch (FailOpenPage e) {
			logger.warn(String.format("CANT OPEN SE PAGE(搜索引擎页面打开失败) %s", e.toString()));
		}
		if (Judge.isEmpty(locationStr)) {
			location = webPage;
		} else
			location = URI.create(locationStr);
		JSONArray imgArray = new JSONArray();
		startIndex=0;
		totalImage=-1;
		URI target = null;
		do {
			try {
				target = nextPage(target, startIndex);
				// 向搜索引擎请求获取相似图片
				jsonResp = getJSON(target, null, -1L, new BasicNameValuePair("Referer", location.toString()));
				if (isValidResp()) {
					imgArray = getArrayFromJsonResp();
					for (int i = 0; i < imgArray.length() && !isFinished.get(); i++) {
						// 页循环,将当前页中的所有链接提交任务
						JSONObject jo = imgArray.getJSONObject(i);
						if (0 < jo.length()) {
							jo.put(ImgJsonDecoder.KEY_MD5REF, md5Ref);
							jo.put(ImgJsonDecoder.KEY_KEYWORD, keyword);
							jo.put(ImgJsonDecoder.KEY_DECODER, getImgJsonDecoder().getClass().getName());
							queueManager.push(new RemoteImageWOC(jo));
						}
					}
				} else if (!isContinue())
					break;
			} catch (JSONException e) {
				logger.error("JSON解析错误,请检查搜索引擎返回的json数据:{} {}",e.getMessage(),jsonResp);
				System.exit(1);
			} finally {				
			}
			startIndex += getPageSize();
		} while (!(isLast() ||isFinished.get()));
		return imgArray;
	}

	/**
	 * 根据 {@link #jsonResp}中的错误信息判断是不是要继续循环
	 * @return
	 * @throws JSONException 
	 */
	protected boolean isContinue() throws JSONException {
		return true;
	}
	protected final JSONArray getArrayFromJsonResp() throws JSONException {
		try {
			return jsonResp.getJSONArray(getArrayKey());
		} catch (JSONException e) {
			logger.error(String.format("CAN'T GET JSONArray from JSON %s", e.toString()));
			throw e;
		}
	}
}
